package jccr;

/**
 * Coordinates a choice between two ports, the first port that gets an
 * enqueued argument will fire and the other will never be called.
 * @author dpet
 * 
 */
public class ChoiceCoordinator extends CoordinatorBase {

	public ChoiceCoordinator( DispatcherQueue dispatcher, RawPort port1, RawPort port2 ) {
		super(dispatcher, false);
		
		if ( port1 == null || port2 == null )
			throw new IllegalArgumentException();
		
		_active = true;
		_port1 = port1;
		_port1.setCoordinator(this);
		_port2 = port2;
		_port2.setCoordinator(this);
	}
		
	public Iterable<Task> coordinate( Object source ) {		
		
		RawPort port = null;
		Object argument = null;
		
		synchronized( this ) {
			
			if ( !_active )
				return null;
			
			/* check the ports for messages; start with the port that generated this 
			 * coordination request. If the .ctor was the source, then start with _port1.
			 */
			if ( source == this ) {
				// coordinate requested by ctor, check both port1 and port2
				// TODO: support ctor requrest
				return null;
			}
			else {
				// check the enqueued port
				assert( source instanceof RawPort );
				port = (RawPort)source;
				argument = port.dequeueRaw();
				// if argument is null then we have nothing to do
				if ( argument == null )
					return null;
				
				disconnectPorts();
			}			
		}
		
		/* we should now have port and argument on the stack and an "empty"
		 * object; assert all these assumptions then execute the port.
		 */
		assert( port != null && argument != null );
		assert( _port1 == null && _port2 == null );
		
		execute(port, argument);	
		return null;
	}
	
	protected Iterable<Task> safeCoordinate( Object source ) {
		
		return null;
	}
	
	void disconnectPorts() {
		_port1.setCoordinator(null);
		_port1 = null;
		_port2.setCoordinator(null);
		_port2 = null;
		_active = false;
	}
		
	boolean _active;
	RawPort _port1;
	RawPort _port2;
}
